package com.smart.community.commons.config;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import lombok.extern.slf4j.Slf4j;

/**
 * 统一的Jackson配置类
 * 
 * 功能说明：
 * 1. 提供全局ObjectMapper配置，支持API响应序列化（不含类型信息）
 * 2. 提供Redis专用的ObjectMapper配置，支持类型安全缓存（含类型信息）
 * 3. 支持Java 8时间类型序列化
 * 4. 统一JSON序列化格式
 * 5. 分离缓存序列化与接口序列化，避免类型信息泄露
 * 6. 配置接口返回专用序列化器，确保前端接收纯净JSON
 * 
 * @author Wu.Liang
 * @version 3.0.0 - 分离缓存序列化与接口序列化
 * @since 2024-12-21
 * @updated 2025-01-30 - 根据Redis缓存处理Spring框架缓存注解序列化方案重构
 */
@Slf4j
@Configuration
public class JacksonConfig {

    /**
     * 日期时间格式化器
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 日期格式化器
     */
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    
    /**
     * 时间格式化器
     */
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");

    /**
     * 配置全局ObjectMapper（用于API响应序列化）
     * 
     * 注意：此ObjectMapper不包含类型信息，用于API响应序列化
     * 
     * @return ObjectMapper
     */
    @Bean
    @Primary
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper() {
        log.info("🔧 初始化全局Jackson ObjectMapper（API响应序列化）...");
        
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 重要：完全禁用所有类型信息注入，用于API响应序列化
        objectMapper.deactivateDefaultTyping();
        
        // 配置序列化特性
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        
        // 配置反序列化特性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
        objectMapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
        objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
        
        // 配置映射特性
        objectMapper.configure(MapperFeature.USE_GETTERS_AS_SETTERS, false);
        objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, false);
        objectMapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true);
        
        // 配置解析特性
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        
        // 配置生成特性
        objectMapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false);
        objectMapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false);
        
        // 设置包含策略
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        // 注册Java时间模块
        objectMapper.registerModule(javaTimeModule());
        
        // 注册自定义模块
        objectMapper.registerModule(customModule());
        
        log.info("✅ 全局Jackson ObjectMapper初始化完成（API响应序列化）");
        return objectMapper;
    }
    
    /**
     * 配置Redis专用的ObjectMapper（用于缓存序列化）
     * 
     * 解决BigDecimal反序列化问题：
     * 使用ObjectMapper.DefaultTyping.NON_FINAL配置，让Jackson对JDK内置类型（如BigDecimal）自动识别，
     * 无需@class类型信息，同时保留自定义POJO的类型信息
     * 
     * @return ObjectMapper
     */
    @Bean("redisObjectMapper")
    @ConditionalOnMissingBean(name = "redisObjectMapper")
    public ObjectMapper redisObjectMapper() {
        log.info("🔧 初始化Redis专用Jackson ObjectMapper（缓存序列化）...");
        
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 重要：配置类型检查，解决BigDecimal反序列化问题
        // 使用NON_FINAL配置，让Jackson对JDK内置类型（如BigDecimal）自动识别，无需@class类型信息
        objectMapper.activateDefaultTyping(
            com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator.instance,
            ObjectMapper.DefaultTyping.NON_FINAL // 非final类型需要类型信息（如自定义POJO）
            // NON_FINAL表示：final类型（如BigDecimal、String）无需类型信息，非final类型需要
        );
        
        // 配置序列化特性
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
        
        // 配置反序列化特性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
        objectMapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
        objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
        
        // 配置映射特性
        objectMapper.configure(MapperFeature.USE_GETTERS_AS_SETTERS, false);
        objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, false);
        objectMapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true);
        
        // 设置包含策略
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        // 注册Java时间模块
        objectMapper.registerModule(javaTimeModule());
        
        // 注册自定义模块
        objectMapper.registerModule(customModule());
        
        log.info("✅ Redis专用Jackson ObjectMapper初始化完成（缓存序列化）");
        return objectMapper;
    }
    
    /**
     * Java时间模块
     * 
     * @return JavaTimeModule
     */
    @Bean
    @ConditionalOnMissingBean
    public JavaTimeModule javaTimeModule() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        
        // 注册LocalDateTime序列化器和反序列化器
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
        
        // 注册LocalDate序列化器和反序列化器
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
        
        // 注册LocalTime序列化器和反序列化器
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMATTER));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
        
        return javaTimeModule;
    }
    
    /**
     * 自定义模块
     * 
     * @return SimpleModule
     */
    @Bean(name = "customModule")
    public SimpleModule customModule() {
        SimpleModule customModule = new SimpleModule();
        
        // 注册BigDecimal序列化器（支持类型信息）
        customModule.addSerializer(BigDecimal.class, new JsonSerializer<BigDecimal>() {
            @Override
            public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                if (value != null) {
                    gen.writeString(value.stripTrailingZeros().toPlainString());
                } else {
                    gen.writeNull();
                }
            }
            
            @Override
            public void serializeWithType(BigDecimal value, JsonGenerator gen, SerializerProvider serializers, 
                                        com.fasterxml.jackson.databind.jsontype.TypeSerializer typeSer) throws IOException {
                // 对于BigDecimal类型，直接序列化值，不添加类型信息
                // 这样可以避免"Type id handling not implemented"错误
                serialize(value, gen, serializers);
            }
        });
        
        // 注册BigDecimal反序列化器
        customModule.addDeserializer(BigDecimal.class, new JsonDeserializer<BigDecimal>() {
            @Override
            public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                String value = p.getValueAsString();
                return value != null ? new BigDecimal(value) : null;
            }
        });
        
        return customModule;
    }
    
    /**
     * 获取日期时间格式化器
     * 
     * @return 日期时间格式化器
     */
    public static DateTimeFormatter getDateTimeFormatter() {
        return DATE_TIME_FORMATTER;
    }
    
    /**
     * 获取日期格式化器
     * 
     * @return 日期格式化器
     */
    public static DateTimeFormatter getDateFormatter() {
        return DATE_FORMATTER;
    }
    
    /**
     * 获取时间格式化器
     * 
     * @return 时间格式化器
     */
    public static DateTimeFormatter getTimeFormatter() {
        return TIME_FORMATTER;
    }
    
    /**
     * 配置接口返回JSON的序列化器（不含类型信息）
     * 
     * 注意：此配置仅影响接口返回，不影响缓存序列化
     * 确保Controller返回给前端的JSON不含类型信息
     * 
     * @return MappingJackson2HttpMessageConverter
     */
    @Bean
    @ConditionalOnMissingBean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        log.info("🔧 初始化接口返回专用序列化器（不含类型信息）...");
        
        // 接口专用ObjectMapper：不保留类型信息
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 重要：完全禁用所有类型信息注入，用于API响应序列化
        objectMapper.deactivateDefaultTyping();
        
        // 配置序列化特性
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        
        // 配置反序列化特性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
        objectMapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
        objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
        
        // 配置映射特性
        objectMapper.configure(MapperFeature.USE_GETTERS_AS_SETTERS, false);
        objectMapper.configure(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, false);
        objectMapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true);
        
        // 设置包含策略
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        // 注册Java时间模块
        objectMapper.registerModule(javaTimeModule());
        
        // 注册自定义模块
        objectMapper.registerModule(customModule());

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper);
        
        log.info("✅ 接口返回专用序列化器初始化完成（不含类型信息）");
        return converter;
    }
} 